package com.example.event_resource_java.oss.server.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.*;
import com.example.event_resource_java.commons.enums.EnumErrorCode;
import com.example.event_resource_java.commons.util.ConstantPropertiesUtil;
import com.example.event_resource_java.oss.server.OssService;
import com.example.event_resource_java.starinside.exception.IFastException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * 上传阿里云OSS实现类
 */
@Service
@AllArgsConstructor
@Slf4j
public class OssServiceImpl implements OssService {

    @Override
    public String uploadFileOssNoPrefix(MultipartFile file) {
        //地域节点
        String endpoint = ConstantPropertiesUtil.END_POINT;
        // 阿里云主账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维，请登录 https://ram.console.aliyun.com 创建RAM账号
        String accessKeyId = ConstantPropertiesUtil.ACCESS_KEY_ID;
        String accessKeySecret = ConstantPropertiesUtil.ACCESS_KEY_SECRET;
        String bucketName = ConstantPropertiesUtil.BUCKET_NAME;
        String bucketPath = ConstantPropertiesUtil.BUCKET_PATH;

        try {
            // 创建OSSClient2.8.3实例
            OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
            //上传文件流
            InputStream inputStream = file.getInputStream();
            String filename = file.getOriginalFilename();

            //2019/11/17/01.jpg
            //获取当前日期，转换/2019/11/17
            SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyy/MM/dd");
            String timeUrl = simpleDateFormat.format(new Date());
            filename =timeUrl+"/"+filename;

            try {
                ossClient.putObject(bucketName, filename, inputStream);
                log.info("阿里云上传文件成功，bucketName:{},key:{},url:{}", bucketName, accessKeyId, bucketPath);
            }catch(Exception e) {
                log.warn("阿里云上传文件失败：{},bucketName:{},key:{}", e.getMessage(), bucketName, accessKeyId);
                throw new IFastException(EnumErrorCode.FileUploadError.getCodeStr());
            }finally {
                ossClient.shutdown();
            }
            //返回上传之后url地址--例如： https://guli-edu-191117.oss-cn-beijing.aliyuncs.com/7.jpg
            String url = "https://" + bucketPath + "/" + filename;
            return url;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public String uploadFileOss(MultipartFile file) {
        //地域节点
        String endpoint = ConstantPropertiesUtil.END_POINT;
        // 阿里云主账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维，请登录 https://ram.console.aliyun.com 创建RAM账号
        String accessKeyId = ConstantPropertiesUtil.ACCESS_KEY_ID;
        String accessKeySecret = ConstantPropertiesUtil.ACCESS_KEY_SECRET;
        String bucketName = ConstantPropertiesUtil.BUCKET_NAME;
        String bucketPath = ConstantPropertiesUtil.BUCKET_PATH;

        try {
            // 创建OSSClient2.8.3实例
            OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
            //上传文件流
            InputStream inputStream = file.getInputStream();
            String filename = file.getOriginalFilename();

            //添加一个UUID值
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            //拼接到filename前面
            filename =uuid+filename;
            //2019/11/17/01.jpg
            //获取当前日期，转换/2019/11/17
            SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyy/MM/dd");
            String timeUrl = simpleDateFormat.format(new Date());
            filename =timeUrl+"/"+filename;

            try {
                ossClient.putObject(bucketName, filename, inputStream);
                log.info("阿里云上传文件成功，bucketName:{},key:{},url:{}", bucketName, accessKeyId, bucketPath);
            }catch(Exception e) {
                log.warn("阿里云上传文件失败：{},bucketName:{},key:{}", e.getMessage(), bucketName, accessKeyId);
                throw new IFastException(EnumErrorCode.FileUploadError.getCodeStr());
            }finally {
                ossClient.shutdown();
            }
            //返回上传之后url地址--例如： https://guli-edu-191117.oss-cn-beijing.aliyuncs.com/7.jpg
            String url = "https://" + bucketPath + "/" + filename;
            return url;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }



    @Override
    public String uploadFileOss2(MultipartFile file) {
        //地域节点
        String endpoint = ConstantPropertiesUtil.END_POINT;
        // 阿里云主账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维，请登录 https://ram.console.aliyun.com 创建RAM账号
        String accessKeyId = ConstantPropertiesUtil.ACCESS_KEY_ID;
        String accessKeySecret = ConstantPropertiesUtil.ACCESS_KEY_SECRET;
        String bucketName = ConstantPropertiesUtil.BUCKET_NAME;
        String bucketPath = ConstantPropertiesUtil.BUCKET_PATH;


        OSS ossClient=null;
        try {
            Date date = new Date();
            String beginTime = date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
            System.out.println("fileUploadZone-开始上传时间："+beginTime);
            //获取文件的原始名字
            String originalfileName = file.getOriginalFilename();
            //文件后缀
            String suffix = originalfileName.substring(originalfileName.lastIndexOf(".") + 1);
            //重新命名文件，文件夹要是改动，app记录删除的地方一并改动

            //添加一个UUID值
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            //拼接到filename前面
            originalfileName =uuid+originalfileName;
            String url = "https://" + bucketPath + "/" + originalfileName;
            // 创建OSSClient实例。
            ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
            // 创建InitiateMultipartUploadRequest对象。
            InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, originalfileName);
            // 如果需要在初始化分片时设置文件存储类型，请参考以下示例代码。
            // ObjectMetadata metadata = new ObjectMetadata();
            // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            // request.setObjectMetadata(metadata);
            // 初始化分片。
            InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
            // 返回uploadId，它是分片上传事件的唯一标识，可以根据这个uploadId发起相关的操作，如取消分片上传、查询分片上传等。
            String uploadId = upresult.getUploadId();
            // partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
            List<PartETag> partETags = new ArrayList<PartETag>();
            // 计算文件有多少个分片。
            // 2MB
            final long partSize = 2 * 1024 * 1024L;
            long fileLength = file.getSize();
            int partCount = (int) (fileLength / partSize);
            if (fileLength % partSize != 0) {
                partCount++;
            }
            // 遍历分片上传。
            for (int i = 0; i < partCount; i++) {
                long startPos = i * partSize;
                long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
                // 跳过已经上传的分片。
                InputStream instream = file.getInputStream();
                instream.skip(startPos);
                UploadPartRequest uploadPartRequest = new UploadPartRequest();
                uploadPartRequest.setBucketName(bucketName);
                uploadPartRequest.setKey(originalfileName);
                uploadPartRequest.setUploadId(uploadId);
                uploadPartRequest.setInputStream(instream);
                // 设置分片大小。除了最后一个分片没有大小限制，其他的分片最小为100 KB。
                uploadPartRequest.setPartSize(curPartSize);
                // 设置分片号。每一个上传的分片都有一个分片号，取值范围是1~10000，如果超出这个范围，OSS将返回InvalidArgument的错误码。
                uploadPartRequest.setPartNumber(i + 1);
                // 每个分片不需要按顺序上传，甚至可以在不同客户端上传，OSS会按照分片号排序组成完整的文件。
                UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
                // 每次上传分片之后，OSS的返回结果包含PartETag。PartETag将被保存在partETags中。
                partETags.add(uploadPartResult.getPartETag());
            }
            /**
             * 创建CompleteMultipartUploadRequest对象。
             * 在执行完成分片上传操作时，需要提供所有有效的partETags。OSS收到提交的partETags后，会逐一验证每个分片的有效性。
             * 当所有的数据分片验证通过后，OSS将把这些分片组合成一个完整的文件。
             */
            CompleteMultipartUploadRequest uploadRequest = new CompleteMultipartUploadRequest(bucketName, originalfileName, uploadId, partETags);
            // 在完成文件上传的同时设置文件访问权限。
            uploadRequest.setObjectACL(CannedAccessControlList.PublicRead);
            // 完成上传。
            ossClient.completeMultipartUpload(uploadRequest);
            // 关闭OSSClient。
            ossClient.shutdown();
            Date date2 = new Date();
            String endTime = date2.getHours() + ":" + date2.getMinutes() + ":" + date2.getSeconds();
            System.out.println("fileUploadZone-结束上传时间："+endTime+" 耗时："+(date2.getTime()-date.getTime())/1000);
            return url;
        } catch (Exception e) {
            e.printStackTrace();
            ossClient.shutdown();
            return "操作失败";
        }

    }



    @Override
    public String uploadUrlFileOss(MultipartFile file, String url) {
        //地域节点
        String endpoint = ConstantPropertiesUtil.END_POINT;
        // 阿里云主账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维，请登录 https://ram.console.aliyun.com 创建RAM账号
        String accessKeyId = ConstantPropertiesUtil.ACCESS_KEY_ID;
        String accessKeySecret = ConstantPropertiesUtil.ACCESS_KEY_SECRET;
        String bucketName = ConstantPropertiesUtil.BUCKET_NAME;
        String bucketPath = ConstantPropertiesUtil.BUCKET_PATH;

        try {
            // 创建OSSClient2.8.3实例
            OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
            //上传文件流
            InputStream inputStream = file.getInputStream();
            String filename = file.getOriginalFilename();
            //严重阿里云OSS是否存在这个文件
            boolean  foo=  ossClient.doesObjectExist(bucketName,url);
            if(foo){
                String url1 = "https://" + bucketPath + "/" + url;
                return url1;
            }
            //添加一个UUID值
            // String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            //拼接到filename前面
            // filename =uuid+filename;

            //2019/11/17/01.jpg
            //获取当前日期，转换/2019/11/17
            SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyy/MM/dd");
            String timeUrl = simpleDateFormat.format(new Date());
            filename =url;

            ObjectMetadata meta = new ObjectMetadata();
            meta.setContentType("image/jpg");

            try {
                ossClient.putObject(bucketName, filename, inputStream,meta);
                log.info("阿里云上传文件成功，bucketName:{},key:{},url:{}", bucketName, accessKeyId, bucketPath);
            }catch(Exception e) {
                log.warn("阿里云上传文件失败：{},bucketName:{},key:{}", e.getMessage(), bucketName, accessKeyId);
                throw new IFastException(EnumErrorCode.FileUploadError.getCodeStr());
            }finally {
                ossClient.shutdown();
            }
            //返回上传之后url地址--例如： https://guli-edu-191117.oss-cn-beijing.aliyuncs.com/7.jpg
            String url1 = "https://" + bucketPath + "/" + filename;
            return url1;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }


    }
//
//    public static String upload(String bucketName, String key, InputStream input) {
//        if(StringUtils.isBlank(bucketName) || StringUtils.isBlank(key) || input==null) {
//           throw new IFastException(EnumErrorCode.FileUploadError.getCodeStr());
//        }
//
//        OSS ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
//        try {
//            ossClient.putObject(bucketName, key, input);
//            Date expiration = DateUtils.addYears(new Date(), 10); // 设置URL过期时间为10年
//            String url = ossClient.generatePresignedUrl(bucketName, key, expiration).toString();
//            log.info("阿里云上传文件成功，bucketName:{},key:{},url:{}", bucketName, key, url);
//           return url;
//        }catch(Exception e) {
//            log.warn("阿里云上传文件失败：{},bucketName:{},key:{}", e.getMessage(), bucketName, key);
//            throw new IFastException(EnumErrorCode.FileUploadError.getCodeStr());
//        }finally {
//            ossClient.shutdown();
//        }
//
//    }
}
